﻿using Microsoft.Extensions.Configuration;
using FrameworkCore.Constants;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using System.IO.Compression;
using System.Reflection;
using System.Text.RegularExpressions;

namespace FrameworkCore.Extensions;

/// <summary>
/// 应用程序部分管理
/// </summary>
public static partial class ApplicationPartManagerExtensions
{
    #region Methods

    /// <summary>
    /// 初始化模块
    /// </summary>
    /// <param name="applicationPartManager"></param>
    public static void InitializeModules(this ApplicationPartManager applicationPartManager)
    {
        ArgumentNullException.ThrowIfNull(applicationPartManager);

        string moduleDirectory = GetModulesDirectory();
        string packagesDirectory = GetPackagesDirectory();

        LoadModule(packagesDirectory);

        foreach (var moduleAssemblyFile in Directory.EnumerateFiles(moduleDirectory, GlobalConstants.AssemblySuffix))
        {
            string fileName = Path.GetFileName(moduleAssemblyFile);
            if (fileName.StartsWith(GlobalConstants.ModulePrefix, StringComparison.OrdinalIgnoreCase)) // 忽略大小写比较
            {
                Assembly assembly = Assembly.LoadFrom(moduleAssemblyFile);
                applicationPartManager.ApplicationParts.Add(new AssemblyPart(assembly));
            }
        }
    }

    /// <summary>
    /// 获取模块目录
    /// </summary>
    /// <returns></returns>
    public static string GetModulesDirectory(List<string>? modulePaths = null)
    {
        modulePaths = modulePaths ?? ConfigurationsExtensions.GetGlobalSection<List<string>>("ModulePaths") ?? new List<string>();

        var moduleDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory);
        foreach (var item in modulePaths)
        {
            moduleDirectory = Path.Combine(moduleDirectory, item);
        }
        Directory.CreateDirectory(moduleDirectory);

        return moduleDirectory;
    }

    /// <summary>
    /// 获取模块目录
    /// </summary>
    /// <returns></returns>
    public static string GetPackagesDirectory()
    {
        return Path.Combine(GetModulesDirectory(), GlobalConstants.PackagesFolderName);
    }

    public static void LoadModule(string packagesPaths) 
    {
        var modulesDirectory = GetModulesDirectory();
        var existingDllFilesToDelete = Directory.GetFiles(modulesDirectory, GlobalConstants.AssemblySuffix);
        foreach (var dllFile in existingDllFilesToDelete)
        {
            try
            {
                File.Delete(dllFile);
                Console.WriteLine($"清理文件：{dllFile}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"无法删除文件 {dllFile}: {ex.Message}");
            }
        }

        LoadAndExecuteAllNupkgFiles(packagesPaths, modulesDirectory);
    }

    public static string ExtractPackage(string packagePath, string extractPath)
    {
        // 创建一个临时目录来解压缩
        string tempDir = Path.Combine(extractPath, Path.GetRandomFileName());
        Directory.CreateDirectory(tempDir);

        // 解压缩 NuGet 包
        ZipFile.ExtractToDirectory(packagePath, tempDir);

        return tempDir;
    }

    public static void LoadAndExecuteDll(string packagesPaths, string modulesDirectory)
    {
        // 解压 NuGet 包并获取解压后的目录
        string tempDir = ExtractPackage(packagesPaths, modulesDirectory);

        string[] allFiles = Directory.GetFiles(tempDir, "*.*", SearchOption.AllDirectories);

        foreach (string file in allFiles)
        {
            if (IsIgnoreNugetFile(file))
                continue;
            try
            {
                string sourceFile = file;
                string destinationFile = Path.Combine(modulesDirectory, Path.GetFileName(file));
                // 如果目标文件已经存在，则先删除
                if (File.Exists(destinationFile))
                {
                    File.Delete(destinationFile);
                }
                File.Move(file, Path.Combine(modulesDirectory, Path.GetFileName(file)));
            }
            catch (Exception ex)
            {
                Console.WriteLine($"未能加载程序集: {file}");
                Console.WriteLine($"错误: {ex.Message}");
            }
        }

        Directory.Delete(tempDir, true);
    }

    public static void LoadAndExecuteAllNupkgFiles(string packagesPaths, string modulesDirectory)
    {
        if (!Directory.Exists(packagesPaths))
        {
            Directory.CreateDirectory(packagesPaths);
        }
        string[] nupkgFiles = Directory.GetFiles(packagesPaths, $"*{GlobalConstants.NugetPackageSuffix}");

        foreach (string nupkgFile in nupkgFiles.Where(x => x.Contains(GlobalConstants.ModulePrefix)))
        {
            LoadAndExecuteDll(nupkgFile, modulesDirectory);
        }
    }

    #endregion

    #region 私有方法
    private static bool IsIgnoreNugetFile(string filePath) 
    {
        string[] fileNamesSuffix = GlobalConstants.IgnoreNugetFileSuffixs.Replace("^", "").Split("|");
        foreach (string item in fileNamesSuffix) 
        {
            if (filePath.EndsWith(item, StringComparison.OrdinalIgnoreCase))
            {
                return true;
            }
        }
        return false;
    }
    #endregion
}
